package com.dzsw.javabase.str;

import cn.hutool.core.util.HexUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configurator;

import java.math.BigDecimal;

public class StringBase {

    private static Logger logger = LogManager.getLogger(StringBase.class);

    public static void main(String[] args) {
        Configurator.initialize("StringBase", StringBase.class.getClassLoader(), "classpath:log4j2.xml");
        str1();
        str2();
    }

    public static void str1() {
        System.out.println("===============================================   str1 start   ==============================================\n");
        NullPointerException ex = new NullPointerException();
        int hashCode = System.identityHashCode(ex);
        System.out.printf("hashCode = 0x%s\n", HexUtil.toHex(hashCode));
        System.out.printf("null = 0x%s\n", HexUtil.toHex(System.identityHashCode(null)));
        System.out.printf("hashCode = 0x%x\n", hashCode);

        String s1 = "hello";
        String s2 = "hello";
        String s3 = new String("hello");
        StringBuilder sb = new StringBuilder("hello");
        System.out.printf("s1 = 0x%s\n", HexUtil.toHex(System.identityHashCode(s1)));
        System.out.printf("s2 = 0x%s\n", HexUtil.toHex(System.identityHashCode(s2)));
        System.out.printf("s3 = 0x%s\n", HexUtil.toHex(System.identityHashCode(s3)));
        System.out.printf("sb = 0x%s\n", HexUtil.toHex(System.identityHashCode(sb.toString())));

        String strNum = "1.01";
        BigDecimal b = new BigDecimal(strNum);
        System.out.printf("b = 0x%s\n", b);

        String s4 = s3.intern();
        System.out.printf("s4 = 0x%s\n", HexUtil.toHex(System.identityHashCode(s4)));
        System.out.printf("s3.intern() == s2 ? : 0x%s\n", s3.intern() == s2);
        System.out.printf("s4 == s2 ? : 0x%s\n", s4 == s2);
        System.out.printf("===============================================   str1 end   ==============================================\n");
    }


    public static void str2() {
        System.out.println("\r\n");
        logger.info(" ===============================================   str2 start   ==============================================");

        String a = "hello";
        String b = "hello";

        String newA = new String("hello");
        String newB = new String("hello");

        String newAa = new String(a);
        String newBb = new String(b);

        logger.info("****** Testing Object == ******");
        logger.info("a == b ? : {}", a == b);
        logger.info("newA == newB ? : {}", newA == newB);
        logger.info("newA == a ? : {}", newA == a);
        logger.info("newB == b ? : {}", newB == b);
        logger.info("newAa == newBb ? : {}", newAa == newBb);
        logger.info("newAa == newA ? : {}", newAa == newA);
        logger.info("newB == newBb ? : {}", newB == newBb);

        logger.info("****** Testing String Object intern method == ******");
        logger.info("a.intern() == b.intern() ? : {}", a.intern() == b.intern());
        logger.info("newA.intern() == newB.intern() ? : {}", newA.intern() == newB.intern());
        logger.info("newA.intern() == a.intern() ? : {}", newA.intern() == a.intern());
        logger.info("b.intern() == newB.intern() ? : {}", b.intern() == newB.intern());
        logger.info("a.intern() == a ? : {}", a.intern() == a);
        logger.info("newA.intern() == newA ? : {}", newA.intern() == newA);

        logger.info("****** Testing String Object equals ******");
        logger.info("a.equals(newA) ? : {}", a.equals(newA));

        logger.info("****** Testing Object splice ******");
        String c = "hel";
        String d = "lo";
        final String fc = "hel";
        final String finalGetC = getC();

        logger.info("c == fc ? : {}", c == fc);
        logger.info("c == finalGetC ? : {}", c == finalGetC);
        // JVM 对于字符串常量的加号连接，在程序编译器，就将常量字符串的加号优化为连接后的值，因此指向完全相等。
        logger.info("a == (\"hel\" + \"lo\") ? : {}", a == ("hel" + "lo"));
        // 由于在字符串加号连接中存在变量，也就是引用值，而引用值在程序编译器是无法确定的，所以相当于在栈里 new 了一个新的 String 对象，保存在堆内存里。
        logger.info("a == (c + d) ? : {}", a == (c + d));
        logger.info("a == (c + \"lo\") ? : {}", a == (c + "lo"));
        // 当 final 变量时基本数据类型和 String 类型时，如果在编译期间就能知道它的确切值的情况下，编译器会把它当中编译期常量使用。有点类似 C 语言中的宏替换。
        logger.info("a == (fc + \"lo\") ? : {}", a == (fc + "lo"));
        // finalGetC 的值需要在函数调用后才能够确定，所以处理方式相当于在栈里 new 了一个新的 String 对象，保存在堆内存里。
        logger.info("a == (finalGetC + \"lo\") ? : {}", a == (finalGetC + "lo"));

        logger.info(" ===============================================   str2 end   ==============================================");
    }

    private static String getC() {
        return "hel";
    }
}
